home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / tk2.3 / dist / tkCanvArc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-16  |  44.8 KB  |  1,525 lines

  1. /* 
  2.  * tkCanvArc.c --
  3.  *
  4.  *    This file implements arc items for canvas widgets.
  5.  *
  6.  * Copyright 1992 Regents of the University of California.
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkCanvArc.c,v 1.5 92/08/16 15:42:20 ouster Exp $ SPRITE (Berkeley)";
  18. #endif
  19.  
  20. #include <stdio.h>
  21. #include <math.h>
  22. #include "tkInt.h"
  23. #include "tkCanvas.h"
  24.  
  25. /*
  26.  * The structure below defines the record for each arc item.
  27.  */
  28.  
  29. typedef struct ArcItem  {
  30.     Tk_Item header;        /* Generic stuff that's the same for all
  31.                  * types.  MUST BE FIRST IN STRUCTURE. */
  32.     double bbox[4];        /* Coordinates (x1, y1, x2, y2) of bounding
  33.                  * box for oval of which arc is a piece. */
  34.     double start;        /* Angle at which arc begins, in degrees
  35.                  * between 0 and 360. */
  36.     double extent;        /* Extent of arc (angular distance from
  37.                  * start to end of arc) in degrees between
  38.                  * -360 and 360. */
  39.     double *outlinePtr;        /* Points to (x,y) coordinates for points
  40.                  * that define one or two closed polygons
  41.                  * representing the portion of the outline
  42.                  * that isn't part of the arc (the V-shape
  43.                  * for a pie slice or a line-like segment
  44.                  * for a chord).  Malloc'ed. */
  45.     int numOutlinePoints;    /* Number of points at outlinePtr.  Zero
  46.                  * means no space allocated. */
  47.     int width;            /* Width of outline (in pixels). */
  48.     XColor *outlineColor;    /* Color for outline.  NULL means don't
  49.                  * draw outline. */
  50.     XColor *fillColor;        /* Color for filling arc (used for drawing
  51.                  * outline too when style is "arc").  NULL
  52.                  * means don't fill arc. */
  53.     Pixmap fillStipple;        /* Stipple bitmap for filling item. */
  54.     Tk_Uid style;        /* How to draw arc: arc, chord, or pieslice. */
  55.     GC outlineGC;        /* Graphics context for outline. */
  56.     GC fillGC;            /* Graphics context for filling item. */
  57.     double center1[2];        /* Coordinates of center of arc outline at
  58.                  * start (see ComputeArcOutline). */
  59.     double center2[2];        /* Coordinates of center of arc outline at
  60.                  * start+extent (see ComputeArcOutline). */
  61. } ArcItem;
  62.  
  63. /*
  64.  * The definitions below define the sizes of the polygons used to
  65.  * display outline information for various styles of arcs:
  66.  */
  67.  
  68. #define CHORD_OUTLINE_PTS    7
  69. #define PIE_OUTLINE1_PTS    6
  70. #define PIE_OUTLINE2_PTS    7
  71.  
  72. /*
  73.  * Information used for parsing configuration specs:
  74.  */
  75.  
  76. static Tk_ConfigSpec configSpecs[] = {
  77.     {TK_CONFIG_DOUBLE, "-extent", (char *) NULL, (char *) NULL,
  78.     "90", Tk_Offset(ArcItem, extent), TK_CONFIG_DONT_SET_DEFAULT},
  79.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  80.     (char *) NULL, Tk_Offset(ArcItem, fillColor), TK_CONFIG_NULL_OK},
  81.     {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL,
  82.     "black", Tk_Offset(ArcItem, outlineColor), TK_CONFIG_NULL_OK},
  83.     {TK_CONFIG_DOUBLE, "-start", (char *) NULL, (char *) NULL,
  84.     "0", Tk_Offset(ArcItem, start), TK_CONFIG_DONT_SET_DEFAULT},
  85.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  86.     (char *) NULL, Tk_Offset(ArcItem, fillStipple), TK_CONFIG_NULL_OK},
  87.     {TK_CONFIG_UID, "-style", (char *) NULL, (char *) NULL,
  88.     "pieslice", Tk_Offset(ArcItem, style), TK_CONFIG_DONT_SET_DEFAULT},
  89.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  90.     (char *) NULL, 0, TK_CONFIG_NULL_OK, &tkCanvasTagsOption},
  91.     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
  92.     "1", Tk_Offset(ArcItem, width), TK_CONFIG_DONT_SET_DEFAULT},
  93.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  94.     (char *) NULL, 0, 0}
  95. };
  96.  
  97. /*
  98.  * Prototypes for procedures defined in this file:
  99.  */
  100.  
  101. static int        ArcCoords _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  102.                 Tk_Item *itemPtr, int argc, char **argv));
  103. static int        AngleInRange _ANSI_ARGS_((double x, double y,
  104.                 double start, double extent));
  105. static int        ArcToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  106.                 Tk_Item *itemPtr, double *rectPtr));
  107. static double        ArcToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  108.                 Tk_Item *itemPtr, double *coordPtr));
  109. static void        ComputeArcBbox _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  110.                 ArcItem *arcPtr));
  111. static void        ComputeArcOutline _ANSI_ARGS_((ArcItem *arcPtr));
  112. static int        ConfigureArc _ANSI_ARGS_((
  113.                 Tk_Canvas *canvasPtr, Tk_Item *itemPtr, int argc,
  114.                 char **argv, int flags));
  115. static int        CreateArc _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  116.                 struct Tk_Item *itemPtr, int argc, char **argv));
  117. static void        DeleteArc _ANSI_ARGS_((Tk_Item *itemPtr));
  118. static void        DisplayArc _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  119.                 Tk_Item *itemPtr, Drawable dst));
  120. static int        HorizLineToArc _ANSI_ARGS_((double x1, double x2,
  121.                 double y, double rx, double ry,
  122.                 double start, double extent));
  123. static void        ScaleArc _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  124.                 Tk_Item *itemPtr, double originX, double originY,
  125.                 double scaleX, double scaleY));
  126. static void        TranslateArc _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  127.                 Tk_Item *itemPtr, double deltaX, double deltaY));
  128. static int        VertLineToArc _ANSI_ARGS_((double x, double y1,
  129.                 double y2, double rx, double ry,
  130.                 double start, double extent));
  131.  
  132. /*
  133.  * The structures below defines the arc item types by means of procedures
  134.  * that can be invoked by generic item code.
  135.  */
  136.  
  137. Tk_ItemType TkArcType = {
  138.     "arc",                /* name */
  139.     sizeof(ArcItem),            /* itemSize */
  140.     CreateArc,                /* createProc */
  141.     configSpecs,            /* configSpecs */
  142.     ConfigureArc,            /* configureProc */
  143.     ArcCoords,                /* coordProc */
  144.     DeleteArc,                /* deleteProc */
  145.     DisplayArc,                /* displayProc */
  146.     0,                    /* alwaysRedraw */
  147.     ArcToPoint,                /* pointProc */
  148.     ArcToArea,                /* areaProc */
  149.     (Tk_ItemPostscriptProc *) NULL,    /* postscriptProc */
  150.     ScaleArc,                /* scaleProc */
  151.     TranslateArc,            /* translateProc */
  152.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  153.     (Tk_ItemCursorProc *) NULL,        /* cursorProc */
  154.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  155.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  156.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  157.     (Tk_ItemType *) NULL        /* nextPtr */
  158. };
  159.  
  160. #define PI 3.14159265358979323846
  161.  
  162. /*
  163.  * The uid's below comprise the legal values for the "-style"
  164.  * option for arcs.
  165.  */
  166.  
  167. static Tk_Uid arcUid =  NULL;
  168. static Tk_Uid chordUid =  NULL;
  169. static Tk_Uid pieSliceUid = NULL;
  170.  
  171. /*
  172.  *--------------------------------------------------------------
  173.  *
  174.  * CreateArc --
  175.  *
  176.  *    This procedure is invoked to create a new arc item in
  177.  *    a canvas.
  178.  *
  179.  * Results:
  180.  *    A standard Tcl return value.  If an error occurred in
  181.  *    creating the item, then an error message is left in
  182.  *    canvasPtr->interp->result;  in this case itemPtr is
  183.  *    left uninitialized, so it can be safely freed by the
  184.  *    caller.
  185.  *
  186.  * Side effects:
  187.  *    A new arc item is created.
  188.  *
  189.  *--------------------------------------------------------------
  190.  */
  191.  
  192. static int
  193. CreateArc(canvasPtr, itemPtr, argc, argv)
  194.     register Tk_Canvas *canvasPtr;    /* Canvas to hold new item. */
  195.     Tk_Item *itemPtr;            /* Record to hold new item;  header
  196.                      * has been initialized by caller. */
  197.     int argc;                /* Number of arguments in argv. */
  198.     char **argv;            /* Arguments describing arc. */
  199. {
  200.     register ArcItem *arcPtr = (ArcItem *) itemPtr;
  201.  
  202.     if (argc < 4) {
  203.     Tcl_AppendResult(canvasPtr->interp, "wrong # args:  should be \"",
  204.         Tk_PathName(canvasPtr->tkwin), "\" create ",
  205.         itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?",
  206.         (char *) NULL);
  207.     return TCL_ERROR;
  208.     }
  209.  
  210.     /*
  211.      * Carry out once-only initialization.
  212.      */
  213.  
  214.     if (arcUid == NULL) {
  215.     arcUid = Tk_GetUid("arc");
  216.     chordUid = Tk_GetUid("chord");
  217.     pieSliceUid = Tk_GetUid("pieslice");
  218.     }
  219.  
  220.     /*
  221.      * Carry out initialization that is needed in order to clean
  222.      * up after errors during the the remainder of this procedure.
  223.      */
  224.  
  225.     arcPtr->start = 0;
  226.     arcPtr->extent = 90;
  227.     arcPtr->outlinePtr = NULL;
  228.     arcPtr->numOutlinePoints = 0;
  229.     arcPtr->width = 1;
  230.     arcPtr->outlineColor = NULL;
  231.     arcPtr->fillColor = NULL;
  232.     arcPtr->fillStipple = None;
  233.     arcPtr->style = pieSliceUid;
  234.     arcPtr->outlineGC = None;
  235.     arcPtr->fillGC = None;
  236.  
  237.     /*
  238.      * Process the arguments to fill in the item record.
  239.      */
  240.  
  241.     if ((TkGetCanvasCoord(canvasPtr, argv[0], &arcPtr->bbox[0]) != TCL_OK)
  242.         || (TkGetCanvasCoord(canvasPtr, argv[1],
  243.         &arcPtr->bbox[1]) != TCL_OK)
  244.         || (TkGetCanvasCoord(canvasPtr, argv[2],
  245.             &arcPtr->bbox[2]) != TCL_OK)
  246.         || (TkGetCanvasCoord(canvasPtr, argv[3],
  247.             &arcPtr->bbox[3]) != TCL_OK)) {
  248.     return TCL_ERROR;
  249.     }
  250.  
  251.     if (ConfigureArc(canvasPtr, itemPtr, argc-4, argv+4, 0) != TCL_OK) {
  252.     DeleteArc(itemPtr);
  253.     return TCL_ERROR;
  254.     }
  255.     return TCL_OK;
  256. }
  257.  
  258. /*
  259.  *--------------------------------------------------------------
  260.  *
  261.  * ArcCoords --
  262.  *
  263.  *    This procedure is invoked to process the "coords" widget
  264.  *    command on arcs.  See the user documentation for details
  265.  *    on what it does.
  266.  *
  267.  * Results:
  268.  *    Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result.
  269.  *
  270.  * Side effects:
  271.  *    The coordinates for the given item may be changed.
  272.  *
  273.  *--------------------------------------------------------------
  274.  */
  275.  
  276. static int
  277. ArcCoords(canvasPtr, itemPtr, argc, argv)
  278.     register Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  279.     Tk_Item *itemPtr;            /* Item whose coordinates are to be
  280.                      * read or modified. */
  281.     int argc;                /* Number of coordinates supplied in
  282.                      * argv. */
  283.     char **argv;            /* Array of coordinates: x1, y1,
  284.                      * x2, y2, ... */
  285. {
  286.     register ArcItem *arcPtr = (ArcItem *) itemPtr;
  287.     char buffer[500];
  288.  
  289.     if (argc == 0) {
  290.     sprintf(buffer, "%g %g %g %g", arcPtr->bbox[0],
  291.         arcPtr->bbox[1], arcPtr->bbox[2],
  292.         arcPtr->bbox[3]);
  293.     Tcl_SetResult(canvasPtr->interp, buffer, TCL_VOLATILE);
  294.     } else if (argc == 4) {
  295.     if ((TkGetCanvasCoord(canvasPtr, argv[0],
  296.             &arcPtr->bbox[0]) != TCL_OK)
  297.         || (TkGetCanvasCoord(canvasPtr, argv[1],
  298.             &arcPtr->bbox[1]) != TCL_OK)
  299.         || (TkGetCanvasCoord(canvasPtr, argv[2],
  300.             &arcPtr->bbox[2]) != TCL_OK)
  301.         || (TkGetCanvasCoord(canvasPtr, argv[3],
  302.             &arcPtr->bbox[3]) != TCL_OK)) {
  303.         return TCL_ERROR;
  304.     }
  305.     ComputeArcBbox(canvasPtr, arcPtr);
  306.     } else {
  307.     sprintf(canvasPtr->interp->result,
  308.         "wrong # coordinates:  expected 0 or 4, got %d",
  309.         argc);
  310.     return TCL_ERROR;
  311.     }
  312.     return TCL_OK;
  313. }
  314.  
  315. /*
  316.  *--------------------------------------------------------------
  317.  *
  318.  * ConfigureArc --
  319.  *
  320.  *    This procedure is invoked to configure various aspects
  321.  *    of a arc item, such as its outline and fill colors.
  322.  *
  323.  * Results:
  324.  *    A standard Tcl result code.  If an error occurs, then
  325.  *    an error message is left in canvasPtr->interp->result.
  326.  *
  327.  * Side effects:
  328.  *    Configuration information, such as colors and stipple
  329.  *    patterns, may be set for itemPtr.
  330.  *
  331.  *--------------------------------------------------------------
  332.  */
  333.  
  334. static int
  335. ConfigureArc(canvasPtr, itemPtr, argc, argv, flags)
  336.     Tk_Canvas *canvasPtr;    /* Canvas containing itemPtr. */
  337.     Tk_Item *itemPtr;        /* Arc item to reconfigure. */
  338.     int argc;            /* Number of elements in argv.  */
  339.     char **argv;        /* Arguments describing things to configure. */
  340.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  341. {
  342.     register ArcItem *arcPtr = (ArcItem *) itemPtr;
  343.     XGCValues gcValues;
  344.     GC newGC;
  345.     unsigned long mask;
  346.     int i;
  347.  
  348.     if (Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin,
  349.         configSpecs, argc, argv, (char *) arcPtr, flags) != TCL_OK) {
  350.     return TCL_ERROR;
  351.     }
  352.  
  353.     /*
  354.      * A few of the options require additional processing, such as
  355.      * style and graphics contexts.
  356.      */
  357.  
  358.     i = arcPtr->start/360.0;
  359.     arcPtr->start -= i*360.0;
  360.     if (arcPtr->start < 0) {
  361.     arcPtr->start += 360.0;
  362.     }
  363.     i = arcPtr->extent/360.0;
  364.     arcPtr->extent -= i*360.0;
  365.  
  366.     if ((arcPtr->style != arcUid) && (arcPtr->style != chordUid)
  367.         && (arcPtr->style != pieSliceUid)) {
  368.     Tcl_AppendResult(canvasPtr->interp, "bad -style option \"",
  369.         arcPtr->style, "\": must be arc, chord, or pieslice",
  370.         (char *) NULL);
  371.     arcPtr->style = pieSliceUid;
  372.     return TCL_ERROR;
  373.     }
  374.  
  375.     if (arcPtr->width < 0) {
  376.     arcPtr->width = 1;
  377.     }
  378.     if (arcPtr->style == arcUid) {
  379.     if (arcPtr->fillColor == NULL) {
  380.         newGC = None;
  381.     } else {
  382.         gcValues.foreground = arcPtr->fillColor->pixel;
  383.         gcValues.cap_style = CapButt;
  384.         gcValues.line_width = arcPtr->width;
  385.         mask = GCForeground|GCCapStyle|GCLineWidth;
  386.         if (arcPtr->fillStipple != None) {
  387.         gcValues.stipple = arcPtr->fillStipple;
  388.         gcValues.fill_style = FillStippled;
  389.         mask |= GCStipple|GCFillStyle;
  390.         }
  391.         newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
  392.     }
  393.     } else if (arcPtr->outlineColor == NULL) {
  394.     newGC = None;
  395.     } else {
  396.     gcValues.foreground = arcPtr->outlineColor->pixel;
  397.     gcValues.cap_style = CapButt;
  398.     gcValues.line_width = arcPtr->width;
  399.     mask = GCForeground|GCCapStyle|GCLineWidth;
  400.     newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
  401.     }
  402.     if (arcPtr->outlineGC != None) {
  403.     Tk_FreeGC(arcPtr->outlineGC);
  404.     }
  405.     arcPtr->outlineGC = newGC;
  406.  
  407.     if ((arcPtr->fillColor == NULL) || (arcPtr->style == arcUid)) {
  408.     newGC = None;
  409.     } else {
  410.     gcValues.foreground = arcPtr->fillColor->pixel;
  411.     if (arcPtr->style == chordUid) {
  412.         gcValues.arc_mode = ArcChord;
  413.     } else {
  414.         gcValues.arc_mode = ArcPieSlice;
  415.     }
  416.     mask = GCForeground|GCArcMode;
  417.     if (arcPtr->fillStipple != None) {
  418.         gcValues.stipple = arcPtr->fillStipple;
  419.         gcValues.fill_style = FillStippled;
  420.         mask |= GCStipple|GCFillStyle;
  421.     }
  422.     newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
  423.     }
  424.     if (arcPtr->fillGC != None) {
  425.     Tk_FreeGC(arcPtr->fillGC);
  426.     }
  427.     arcPtr->fillGC = newGC;
  428.  
  429.     ComputeArcBbox(canvasPtr, arcPtr);
  430.     return TCL_OK;
  431. }
  432.  
  433. /*
  434.  *--------------------------------------------------------------
  435.  *
  436.  * DeleteArc --
  437.  *
  438.  *    This procedure is called to clean up the data structure
  439.  *    associated with a arc item.
  440.  *
  441.  * Results:
  442.  *    None.
  443.  *
  444.  * Side effects:
  445.  *    Resources associated with itemPtr are released.
  446.  *
  447.  *--------------------------------------------------------------
  448.  */
  449.  
  450. static void
  451. DeleteArc(itemPtr)
  452.     Tk_Item *itemPtr;            /* Item that is being deleted. */
  453. {
  454.     register ArcItem *arcPtr = (ArcItem *) itemPtr;
  455.  
  456.     if (arcPtr->numOutlinePoints != 0) {
  457.     ckfree((char *) arcPtr->outlinePtr);
  458.     }
  459.     if (arcPtr->outlineColor != NULL) {
  460.     Tk_FreeColor(arcPtr->outlineColor);
  461.     }
  462.     if (arcPtr->fillColor != NULL) {
  463.     Tk_FreeColor(arcPtr->fillColor);
  464.     }
  465.     if (arcPtr->fillStipple != None) {
  466.     Tk_FreeBitmap(arcPtr->fillStipple);
  467.     }
  468.     if (arcPtr->outlineGC != None) {
  469.     Tk_FreeGC(arcPtr->outlineGC);
  470.     }
  471.     if (arcPtr->fillGC != None) {
  472.     Tk_FreeGC(arcPtr->fillGC);
  473.     }
  474. }
  475.  
  476. /*
  477.  *--------------------------------------------------------------
  478.  *
  479.  * ComputeArcBbox --
  480.  *
  481.  *    This procedure is invoked to compute the bounding box of
  482.  *    all the pixels that may be drawn as part of an arc.
  483.  *
  484.  * Results:
  485.  *    None.
  486.  *
  487.  * Side effects:
  488.  *    The fields x1, y1, x2, and y2 are updated in the header
  489.  *    for itemPtr.
  490.  *
  491.  *--------------------------------------------------------------
  492.  */
  493.  
  494.     /* ARGSUSED */
  495. static void
  496. ComputeArcBbox(canvasPtr, arcPtr)
  497.     register Tk_Canvas *canvasPtr;    /* Canvas that contains item. */
  498.     register ArcItem *arcPtr;        /* Item whose bbox is to be
  499.                      * recomputed. */
  500. {
  501.     double tmp, center[2], point[2];
  502.  
  503.     /*
  504.      * Make sure that the first coordinates are the lowest ones.
  505.      */
  506.  
  507.     if (arcPtr->bbox[1] > arcPtr->bbox[3]) {
  508.     double tmp;
  509.     tmp = arcPtr->bbox[3];
  510.     arcPtr->bbox[3] = arcPtr->bbox[1];
  511.     arcPtr->bbox[1] = tmp;
  512.     }
  513.     if (arcPtr->bbox[0] > arcPtr->bbox[2]) {
  514.     double tmp;
  515.     tmp = arcPtr->bbox[2];
  516.     arcPtr->bbox[2] = arcPtr->bbox[0];
  517.     arcPtr->bbox[0] = tmp;
  518.     }
  519.  
  520.     ComputeArcOutline(arcPtr);
  521.  
  522.     /*
  523.      * To compute the bounding box, start with the the bbox formed
  524.      * by the two endpoints of the arc.  Then add in the center of
  525.      * the arc's oval (if relevant) and the 3-o'clock, 6-o'clock,
  526.      * 9-o'clock, and 12-o'clock positions, if they are relevant.
  527.      */
  528.  
  529.     arcPtr->header.x1 = arcPtr->header.x2 = arcPtr->center1[0];
  530.     arcPtr->header.y1 = arcPtr->header.y2 = arcPtr->center1[1];
  531.     TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, arcPtr->center2);
  532.     center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2;
  533.     center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2;
  534.     if (arcPtr->style != arcUid) {
  535.     TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, center);
  536.     }
  537.  
  538.     tmp = -arcPtr->start;
  539.     if (tmp < 0) {
  540.     tmp += 360.0;
  541.     }
  542.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  543.     point[0] = arcPtr->bbox[2];
  544.     point[1] = center[1];
  545.     TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, point);
  546.     }
  547.     tmp = 90.0 - arcPtr->start;
  548.     if (tmp < 0) {
  549.     tmp += 360.0;
  550.     }
  551.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  552.     point[0] = center[0];
  553.     point[1] = arcPtr->bbox[1];
  554.     TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, point);
  555.     }
  556.     tmp = 180.0 - arcPtr->start;
  557.     if (tmp < 0) {
  558.     tmp += 360.0;
  559.     }
  560.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  561.     point[0] = arcPtr->bbox[0];
  562.     point[1] = center[1];
  563.     TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, point);
  564.     }
  565.     tmp = 270.0 - arcPtr->start;
  566.     if (tmp < 0) {
  567.     tmp += 360.0;
  568.     }
  569.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  570.     point[0] = center[0];
  571.     point[1] = arcPtr->bbox[3];
  572.     TkIncludePoint(canvasPtr, (Tk_Item *) arcPtr, point);
  573.     }
  574.  
  575.     /*
  576.      * Lastly, expand by the width of the arc (if the arc's outline is
  577.      * being drawn) and add one extra pixel just for safety.
  578.      */
  579.  
  580.     if (arcPtr->outlineColor == NULL) {
  581.     tmp = 1;
  582.     } else {
  583.     tmp = (arcPtr->width + 1)/2 + 1;
  584.     }
  585.     arcPtr->header.x1 -= tmp;
  586.     arcPtr->header.y1 -= tmp;
  587.     arcPtr->header.x2 += tmp;
  588.     arcPtr->header.y2 += tmp;
  589. }
  590.  
  591. /*
  592.  *--------------------------------------------------------------
  593.  *
  594.  * DisplayArc --
  595.  *
  596.  *    This procedure is invoked to draw an arc item in a given
  597.  *    drawable.
  598.  *
  599.  * Results:
  600.  *    None.
  601.  *
  602.  * Side effects:
  603.  *    ItemPtr is drawn in drawable using the transformation
  604.  *    information in canvasPtr.
  605.  *
  606.  *--------------------------------------------------------------
  607.  */
  608.  
  609. static void
  610. DisplayArc(canvasPtr, itemPtr, drawable)
  611.     register Tk_Canvas *canvasPtr;    /* Canvas that contains item. */
  612.     Tk_Item *itemPtr;            /* Item to be displayed. */
  613.     Drawable drawable;            /* Pixmap or window in which to draw
  614.                      * item. */
  615. {
  616.     register ArcItem *arcPtr = (ArcItem *) itemPtr;
  617.     Display *display = Tk_Display(canvasPtr->tkwin);
  618.     int x1, y1, x2, y2, start, extent;
  619.  
  620.     /*
  621.      * Compute the screen coordinates of the bounding box for the item,
  622.      * plus integer values for the angles.
  623.      */
  624.  
  625.     x1 = SCREEN_X(canvasPtr, arcPtr->bbox[0]);
  626.     y1 = SCREEN_Y(canvasPtr, arcPtr->bbox[1]);
  627.     x2 = SCREEN_X(canvasPtr, arcPtr->bbox[2]);
  628.     y2 = SCREEN_Y(canvasPtr, arcPtr->bbox[3]);
  629.     if (x2 <= x1) {
  630.     x2 = x1+1;
  631.     }
  632.     if (y2 <= y1) {
  633.     y2 = y1+1;
  634.     }
  635.     start = (64*arcPtr->start) + 0.5;
  636.     extent = (64*arcPtr->extent) + 0.5;
  637.  
  638.     /*
  639.      * Display filled arc first (if wanted), then outline.
  640.      */
  641.  
  642.     if (arcPtr->fillGC != None) {
  643.     XFillArc(display, drawable, arcPtr->fillGC, x1, y1, (x2-x1),
  644.         (y2-y1), start, extent);
  645.     }
  646.     if (arcPtr->outlineGC != None) {
  647.     XDrawArc(display, drawable, arcPtr->outlineGC, x1, y1, (x2-x1),
  648.         (y2-y1), start, extent);
  649.  
  650.     /*
  651.      * If the outline width is very thin, don't use polygons to draw
  652.      * the linear parts of the outline (this often results in nothing
  653.      * being displayed); just draw lines instead.
  654.      */
  655.  
  656.     if (arcPtr->width <= 2) {
  657.         x1 = SCREEN_X(canvasPtr, arcPtr->center1[0]);
  658.         y1 = SCREEN_Y(canvasPtr, arcPtr->center1[1]);
  659.         x2 = SCREEN_X(canvasPtr, arcPtr->center2[0]);
  660.         y2 = SCREEN_Y(canvasPtr, arcPtr->center2[1]);
  661.  
  662.         if (arcPtr->style == chordUid) {
  663.         XDrawLine(display, drawable, arcPtr->outlineGC,
  664.             x1, y1, x2, y2);
  665.         } else if (arcPtr->style == pieSliceUid) {
  666.         int cx, cy;
  667.     
  668.         cx = SCREEN_X(canvasPtr, (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0);
  669.         cy = SCREEN_Y(canvasPtr, (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0);
  670.         XDrawLine(display, drawable, arcPtr->outlineGC,
  671.             cx, cy, x1, y1);
  672.         XDrawLine(display, drawable, arcPtr->outlineGC,
  673.             cx, cy, x2, y2);
  674.         }
  675.     } else {
  676.         if (arcPtr->style == chordUid) {
  677.         TkFillPolygon(canvasPtr, arcPtr->outlinePtr,
  678.             CHORD_OUTLINE_PTS, drawable, arcPtr->outlineGC);
  679.         } else if (arcPtr->style == pieSliceUid) {
  680.         TkFillPolygon(canvasPtr, arcPtr->outlinePtr,
  681.             PIE_OUTLINE1_PTS, drawable, arcPtr->outlineGC);
  682.         TkFillPolygon(canvasPtr,
  683.             arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  684.             PIE_OUTLINE2_PTS, drawable, arcPtr->outlineGC);
  685.         }
  686.     }
  687.     }
  688. }
  689.  
  690. /*
  691.  *--------------------------------------------------------------
  692.  *
  693.  * ArcToPoint --
  694.  *
  695.  *    Computes the distance from a given point to a given
  696.  *    arc, in canvas units.
  697.  *
  698.  * Results:
  699.  *    The return value is 0 if the point whose x and y coordinates
  700.  *    are coordPtr[0] and coordPtr[1] is inside the arc.  If the
  701.  *    point isn't inside the arc then the return value is the
  702.  *    distance from the point to the arc.  If itemPtr is filled,
  703.  *    then anywhere in the interior is considered "inside"; if
  704.  *    itemPtr isn't filled, then "inside" means only the area
  705.  *    occupied by the outline.
  706.  *
  707.  * Side effects:
  708.  *    None.
  709.  *
  710.  *--------------------------------------------------------------
  711.  */
  712.  
  713.     /* ARGSUSED */
  714. static double
  715. ArcToPoint(canvasPtr, itemPtr, pointPtr)
  716.     Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  717.     Tk_Item *itemPtr;        /* Item to check against point. */
  718.     double *pointPtr;        /* Pointer to x and y coordinates. */
  719. {
  720.     register ArcItem *arcPtr = (ArcItem *) itemPtr;
  721.     double vertex[2], pointAngle, diff, dist, newDist;
  722.     double poly[8], polyDist, width;
  723.     int filled, angleInRange;
  724.  
  725.     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
  726.     filled = 1;
  727.     } else {
  728.     filled = 0;
  729.     }
  730.  
  731.     /*
  732.      * See if the point is within the angular range of the arc.
  733.      * Remember, X angles are backwards from the way we'd normally
  734.      * think of them.  Also, compensate for any eccentricity of
  735.      * the oval.
  736.      */
  737.  
  738.     vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
  739.     vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
  740.     pointAngle = -atan2((pointPtr[1] - vertex[1])
  741.         /(arcPtr->bbox[3] - arcPtr->bbox[1]),
  742.         (pointPtr[0] - vertex[0])/(arcPtr->bbox[2] - arcPtr->bbox[0]));
  743.     pointAngle *= 180/PI;
  744.     diff = pointAngle - arcPtr->start;
  745.     diff -= ((int) (diff/360.0) * 360.0);
  746.     if (diff < 0) {
  747.     diff += 360.0;
  748.     }
  749.     angleInRange = (diff <= arcPtr->extent) ||
  750.         ((arcPtr->extent < 0) && ((diff - 360.0) >= arcPtr->extent));
  751.  
  752.     /*
  753.      * Now perform different tests depending on what kind of arc
  754.      * we're dealing with.
  755.      */
  756.  
  757.     if (arcPtr->style == arcUid) {
  758.     if (angleInRange) {
  759.         return TkOvalToPoint(arcPtr->bbox, (double) arcPtr->width,
  760.             0, pointPtr);
  761.     }
  762.     dist = hypot(pointPtr[0] - arcPtr->center1[0],
  763.         pointPtr[1] - arcPtr->center1[1]);
  764.     newDist = hypot(pointPtr[0] - arcPtr->center2[0],
  765.         pointPtr[1] - arcPtr->center2[1]);
  766.     if (newDist < dist) {
  767.         return newDist;
  768.     }
  769.     return dist;
  770.     }
  771.  
  772.     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
  773.     filled = 1;
  774.     } else {
  775.     filled = 0;
  776.     }
  777.     if (arcPtr->outlineGC == None) {
  778.     width = 0.0;
  779.     } else {
  780.     width = arcPtr->width;
  781.     }
  782.  
  783.     if (arcPtr->style == pieSliceUid) {
  784.     if (width > 1.0) {
  785.         dist = TkPolygonToPoint(arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
  786.             pointPtr);
  787.         newDist = TkPolygonToPoint(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  788.             PIE_OUTLINE2_PTS, pointPtr);
  789.     } else {
  790.         dist = TkLineToPoint(vertex, arcPtr->center1, pointPtr);
  791.         newDist = TkLineToPoint(vertex, arcPtr->center2, pointPtr);
  792.     }
  793.     if (newDist < dist) {
  794.         dist = newDist;
  795.     }
  796.     if (angleInRange) {
  797.         newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr);
  798.         if (newDist < dist) {
  799.         dist = newDist;
  800.         }
  801.     }
  802.     return dist;
  803.     }
  804.  
  805.     /*
  806.      * This is a chord-style arc.  We have to deal specially with the
  807.      * triangular piece that represents the difference between a
  808.      * chord-style arc and a pie-slice arc (for small angles this piece
  809.      * is excluded here where it would be included for pie slices;
  810.      * for large angles the piece is included here but would be
  811.      * excluded for pie slices).
  812.      */
  813.  
  814.     if (width > 1.0) {
  815.     dist = TkPolygonToPoint(arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
  816.             pointPtr);
  817.     } else {
  818.     dist = TkLineToPoint(arcPtr->center1, arcPtr->center2, pointPtr);
  819.     }
  820.     poly[0] = poly[6] = vertex[0];
  821.     poly[1] = poly[7] = vertex[1];
  822.     poly[2] = arcPtr->center1[0];
  823.     poly[3] = arcPtr->center1[1];
  824.     poly[4] = arcPtr->center2[0];
  825.     poly[5] = arcPtr->center2[1];
  826.     polyDist = TkPolygonToPoint(poly, 4, pointPtr);
  827.     if (angleInRange) {
  828.     if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)
  829.         || (polyDist > 0.0)) {
  830.         newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr);
  831.         if (newDist < dist) {
  832.         dist = newDist;
  833.         }
  834.     }
  835.     } else {
  836.     if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)) {
  837.         if (filled && (polyDist < dist)) {
  838.         dist = polyDist;
  839.         }
  840.     }
  841.     }
  842.     return dist;
  843. }
  844.  
  845. /*
  846.  *--------------------------------------------------------------
  847.  *
  848.  * ArcToArea --
  849.  *
  850.  *    This procedure is called to determine whether an item
  851.  *    lies entirely inside, entirely outside, or overlapping
  852.  *    a given area.
  853.  *
  854.  * Results:
  855.  *    -1 is returned if the item is entirely outside the area
  856.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  857.  *    inside the given area.
  858.  *
  859.  * Side effects:
  860.  *    None.
  861.  *
  862.  *--------------------------------------------------------------
  863.  */
  864.  
  865.     /* ARGSUSED */
  866. static int
  867. ArcToArea(canvasPtr, itemPtr, rectPtr)
  868.     Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  869.     Tk_Item *itemPtr;        /* Item to check against arc. */
  870.     double *rectPtr;        /* Pointer to array of four coordinates
  871.                  * (x1, y1, x2, y2) describing rectangular
  872.                  * area.  */
  873. {
  874.     register ArcItem *arcPtr = (ArcItem *) itemPtr;
  875.     double rx, ry;        /* Radii for transformed oval:  these define
  876.                  * an oval centered at the origin. */
  877.     double tRect[4];        /* Transformed version of x1, y1, x2, y2,
  878.                  * for coord. system where arc is centered
  879.                  * on the origin. */
  880.     double center[2], width, angle, tmp;
  881.     double points[20], *pointPtr;
  882.     int numPoints, filled;
  883.     int inside;            /* Non-zero means every test so far suggests
  884.                  * that arc is inside rectangle.  0 means
  885.                  * every test so far shows arc to be outside
  886.                  * of rectangle. */
  887.     int newInside;
  888.  
  889.     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
  890.     filled = 1;
  891.     } else {
  892.     filled = 0;
  893.     }
  894.     if (arcPtr->outlineGC == None) {
  895.     width = 0.0;
  896.     } else {
  897.     width = arcPtr->width;
  898.     }
  899.  
  900.     /*
  901.      * Transform both the arc and the rectangle so that the arc's oval
  902.      * is centered on the origin.
  903.      */
  904.  
  905.     center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
  906.     center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
  907.     tRect[0] = rectPtr[0] - center[0];
  908.     tRect[1] = rectPtr[1] - center[1];
  909.     tRect[2] = rectPtr[2] - center[0];
  910.     tRect[3] = rectPtr[3] - center[1];
  911.     rx = arcPtr->bbox[2] - center[0] + width/2.0;
  912.     ry = arcPtr->bbox[3] - center[1] + width/2.0;
  913.  
  914.     /*
  915.      * Find the extreme points of the arc and see whether these are all
  916.      * inside the rectangle (in which case we're done), partly in and
  917.      * partly out (in which case we're done), or all outside (in which
  918.      * case we have more work to do).  The extreme points include the
  919.      * following, which are checked in order:
  920.      *
  921.      * 1. The outside points of the arc, corresponding to start and
  922.      *      extent.
  923.      * 2. The center of the arc (but only in pie-slice mode).
  924.      * 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc
  925.      *    includes those angles).
  926.      */
  927.  
  928.     pointPtr = points;
  929.     numPoints = 0;
  930.     angle = -arcPtr->start*(PI/180.0);
  931.     pointPtr[0] = rx*cos(angle);
  932.     pointPtr[1] = ry*sin(angle);
  933.     angle += -arcPtr->extent*(PI/180.0);
  934.     pointPtr[2] = rx*cos(angle);
  935.     pointPtr[3] = ry*sin(angle);
  936.     numPoints = 2;
  937.     pointPtr += 4;
  938.  
  939.     if ((arcPtr->style == pieSliceUid) && (arcPtr->extent < 180.0)) {
  940.     pointPtr[0] = 0.0;
  941.     pointPtr[1] = 0.0;
  942.     numPoints++;
  943.     pointPtr += 2;
  944.     }
  945.  
  946.     tmp = -arcPtr->start;
  947.     if (tmp < 0) {
  948.     tmp += 360.0;
  949.     }
  950.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  951.     pointPtr[0] = rx;
  952.     pointPtr[1] = 0.0;
  953.     numPoints++;
  954.     pointPtr += 2;
  955.     }
  956.     tmp = 90.0 - arcPtr->start;
  957.     if (tmp < 0) {
  958.     tmp += 360.0;
  959.     }
  960.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  961.     pointPtr[0] = 0.0;
  962.     pointPtr[1] = -ry;
  963.     numPoints++;
  964.     pointPtr += 2;
  965.     }
  966.     tmp = 180.0 - arcPtr->start;
  967.     if (tmp < 0) {
  968.     tmp += 360.0;
  969.     }
  970.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  971.     pointPtr[0] = -rx;
  972.     pointPtr[1] = 0.0;
  973.     numPoints++;
  974.     pointPtr += 2;
  975.     }
  976.     tmp = 270.0 - arcPtr->start;
  977.     if (tmp < 0) {
  978.     tmp += 360.0;
  979.     }
  980.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  981.     pointPtr[0] = 0.0;
  982.     pointPtr[1] = ry;
  983.     numPoints++;
  984.     pointPtr += 2;
  985.     }
  986.  
  987.     /*
  988.      * Now that we've located the extreme points, loop through them all
  989.      * to see which are inside the rectangle.
  990.      */
  991.  
  992.     inside = (points[0] > tRect[0]) && (points[0] < tRect[2])
  993.         && (points[1] > tRect[1]) && (points[1] < tRect[3]);
  994.     for (pointPtr = points+2; numPoints > 1; pointPtr += 2, numPoints--) {
  995.     newInside = (pointPtr[0] > tRect[0]) && (pointPtr[0] < tRect[2])
  996.         && (pointPtr[1] > tRect[1]) && (pointPtr[1] < tRect[3]);
  997.     if (newInside != inside) {
  998.         return 0;
  999.     }
  1000.     }
  1001.  
  1002.     if (inside) {
  1003.     return 1;
  1004.     }
  1005.  
  1006.     /*
  1007.      * So far, oval appears to be outside rectangle, but can't yet tell
  1008.      * for sure.  Next, test each of the four sides of the rectangle
  1009.      * against the bounding region for the arc.  If any intersections
  1010.      * are found, then return "overlapping".  First, test against the
  1011.      * polygon(s) forming the sides of a chord or pie-slice.
  1012.      */
  1013.  
  1014.     if (arcPtr->style == pieSliceUid) {
  1015.     if (width >= 1.0) {
  1016.         if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
  1017.             rectPtr) != -1)  {
  1018.         return 0;
  1019.         }
  1020.         if (TkPolygonToArea(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  1021.             PIE_OUTLINE2_PTS, rectPtr) != -1) {
  1022.         return 0;
  1023.         }
  1024.     } else {
  1025.         if ((TkLineToArea(center, arcPtr->center1, rectPtr) != -1) ||
  1026.             (TkLineToArea(center, arcPtr->center2, rectPtr) != -1)) {
  1027.         return 0;
  1028.         }
  1029.     }
  1030.     } else if (arcPtr->style == chordUid) {
  1031.     if (width >= 1.0) {
  1032.         if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
  1033.             rectPtr) != -1) {
  1034.         return 0;
  1035.         }
  1036.     } else {
  1037.         if (TkLineToArea(arcPtr->center1, arcPtr->center2,
  1038.             rectPtr) != -1) {
  1039.         return 0;
  1040.         }
  1041.     }
  1042.     }
  1043.  
  1044.     /*
  1045.      * Next check for overlap between each of the four sides and the
  1046.      * outer perimiter of the arc.  If the arc isn't filled, then also
  1047.      * check the inner perimeter of the arc.
  1048.      */
  1049.  
  1050.     if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start,
  1051.         arcPtr->extent)
  1052.         || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry,
  1053.         arcPtr->start, arcPtr->extent)
  1054.         || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry,
  1055.         arcPtr->start, arcPtr->extent)
  1056.         || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry,
  1057.         arcPtr->start, arcPtr->extent)) {
  1058.     return 0;
  1059.     }
  1060.     if ((width > 1.0) && !filled) {
  1061.     rx -= width;
  1062.     ry -= width;
  1063.     if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start,
  1064.             arcPtr->extent)
  1065.         || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry,
  1066.             arcPtr->start, arcPtr->extent)
  1067.         || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry,
  1068.             arcPtr->start, arcPtr->extent)
  1069.         || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry,
  1070.             arcPtr->start, arcPtr->extent)) {
  1071.         return 0;
  1072.     }
  1073.     }
  1074.  
  1075.     /*
  1076.      * The arc still appears to be totally disjoint from the rectangle,
  1077.      * but it's also possible that the rectangle is totally inside the arc.
  1078.      * Do one last check, which is to check one point of the rectangle
  1079.      * to see if it's inside the arc.  If it is, we've got overlap.  If
  1080.      * it isn't, the arc's really outside the rectangle.
  1081.      */
  1082.  
  1083.     if (ArcToPoint(canvasPtr, itemPtr, rectPtr) == 0.0) {
  1084.     return 0;
  1085.     }
  1086.     return -1;
  1087. }
  1088.  
  1089. /*
  1090.  *--------------------------------------------------------------
  1091.  *
  1092.  * ScaleArc --
  1093.  *
  1094.  *    This procedure is invoked to rescale an arc item.
  1095.  *
  1096.  * Results:
  1097.  *    None.
  1098.  *
  1099.  * Side effects:
  1100.  *    The arc referred to by itemPtr is rescaled so that the
  1101.  *    following transformation is applied to all point
  1102.  *    coordinates:
  1103.  *        x' = originX + scaleX*(x-originX)
  1104.  *        y' = originY + scaleY*(y-originY)
  1105.  *
  1106.  *--------------------------------------------------------------
  1107.  */
  1108.  
  1109. static void
  1110. ScaleArc(canvasPtr, itemPtr, originX, originY, scaleX, scaleY)
  1111.     Tk_Canvas *canvasPtr;        /* Canvas containing arc. */
  1112.     Tk_Item *itemPtr;            /* Arc to be scaled. */
  1113.     double originX, originY;        /* Origin about which to scale rect. */
  1114.     double scaleX;            /* Amount to scale in X direction. */
  1115.     double scaleY;            /* Amount to scale in Y direction. */
  1116. {
  1117.     register ArcItem *arcPtr = (ArcItem *) itemPtr;
  1118.  
  1119.     arcPtr->bbox[0] = originX + scaleX*(arcPtr->bbox[0] - originX);
  1120.     arcPtr->bbox[1] = originY + scaleY*(arcPtr->bbox[1] - originY);
  1121.     arcPtr->bbox[2] = originX + scaleX*(arcPtr->bbox[2] - originX);
  1122.     arcPtr->bbox[3] = originY + scaleY*(arcPtr->bbox[3] - originY);
  1123.     ComputeArcBbox(canvasPtr, arcPtr);
  1124. }
  1125.  
  1126. /*
  1127.  *--------------------------------------------------------------
  1128.  *
  1129.  * TranslateArc --
  1130.  *
  1131.  *    This procedure is called to move an arc by a given amount.
  1132.  *
  1133.  * Results:
  1134.  *    None.
  1135.  *
  1136.  * Side effects:
  1137.  *    The position of the arc is offset by (xDelta, yDelta), and
  1138.  *    the bounding box is updated in the generic part of the item
  1139.  *    structure.
  1140.  *
  1141.  *--------------------------------------------------------------
  1142.  */
  1143.  
  1144. static void
  1145. TranslateArc(canvasPtr, itemPtr, deltaX, deltaY)
  1146.     Tk_Canvas *canvasPtr;        /* Canvas containing item. */
  1147.     Tk_Item *itemPtr;            /* Item that is being moved. */
  1148.     double deltaX, deltaY;        /* Amount by which item is to be
  1149.                      * moved. */
  1150. {
  1151.     register ArcItem *arcPtr = (ArcItem *) itemPtr;
  1152.  
  1153.     arcPtr->bbox[0] += deltaX;
  1154.     arcPtr->bbox[1] += deltaY;
  1155.     arcPtr->bbox[2] += deltaX;
  1156.     arcPtr->bbox[3] += deltaY;
  1157.     ComputeArcBbox(canvasPtr, arcPtr);
  1158. }
  1159.  
  1160. /*
  1161.  *--------------------------------------------------------------
  1162.  *
  1163.  * ComputeArcOutline --
  1164.  *
  1165.  *    This procedure creates a polygon describing everything in
  1166.  *    the outline for an arc except what's in the curved part.
  1167.  *    For a "pie slice" arc this is a V-shaped chunk, and for
  1168.  *    a "chord" arc this is a linear chunk (with cutaway corners).
  1169.  *    For "arc" arcs, this stuff isn't relevant.
  1170.  *
  1171.  * Results:
  1172.  *    None.
  1173.  *
  1174.  * Side effects:
  1175.  *    The information at arcPtr->outlinePtr gets modified, and
  1176.  *    storage for arcPtr->outlinePtr may be allocated or freed.
  1177.  *
  1178.  *--------------------------------------------------------------
  1179.  */
  1180.  
  1181. static void
  1182. ComputeArcOutline(arcPtr)
  1183.     register ArcItem *arcPtr;
  1184. {
  1185.     double sin1, cos1, sin2, cos2, angle, halfWidth;
  1186.     double boxWidth, boxHeight;
  1187.     double vertex[2], corner1[2], corner2[2];
  1188.     double *outlinePtr;
  1189.  
  1190.     /*
  1191.      * Make sure that the outlinePtr array is large enough to hold
  1192.      * either a chord or pie-slice outline.
  1193.      */
  1194.  
  1195.     if (arcPtr->numOutlinePoints == 0) {
  1196.     arcPtr->outlinePtr = (double *) ckalloc((unsigned)
  1197.         (26 * sizeof(double)));
  1198.     arcPtr->numOutlinePoints = 22;
  1199.     }
  1200.     outlinePtr = arcPtr->outlinePtr;
  1201.  
  1202.     /*
  1203.      * First compute the two points that lie at the centers of
  1204.      * the ends of the curved arc segment, which are marked with
  1205.      * X's in the figure below:
  1206.      *
  1207.      *
  1208.      *                  * * *
  1209.      *                  *          *
  1210.      *               *      * *      *
  1211.      *             *    *         *    *
  1212.      *            *   *             *   *
  1213.      *             X *               * X
  1214.      *
  1215.      * The code is tricky because the arc can be ovular in shape.
  1216.      * It computes the position for a unit circle, and then
  1217.      * scales to fit the shape of the arc's bounding box.
  1218.      *
  1219.      * Also, watch out because angles go counter-clockwise like you
  1220.      * might expect, but the y-coordinate system is inverted.  To
  1221.      * handle this, just negate the angles in all the computations.
  1222.      */
  1223.  
  1224.     boxWidth = arcPtr->bbox[2] - arcPtr->bbox[0];
  1225.     boxHeight = arcPtr->bbox[3] - arcPtr->bbox[1];
  1226.     angle = -arcPtr->start*PI/180.0;
  1227.     sin1 = sin(angle);
  1228.     cos1 = cos(angle);
  1229.     angle -= arcPtr->extent*PI/180.0;
  1230.     sin2 = sin(angle);
  1231.     cos2 = cos(angle);
  1232.     vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
  1233.     vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
  1234.     arcPtr->center1[0] = vertex[0] + cos1*boxWidth/2.0;
  1235.     arcPtr->center1[1] = vertex[1] + sin1*boxHeight/2.0;
  1236.     arcPtr->center2[0] = vertex[0] + cos2*boxWidth/2.0;
  1237.     arcPtr->center2[1] = vertex[1] + sin2*boxHeight/2.0;
  1238.  
  1239.     /*
  1240.      * Next compute the "outermost corners" of the arc, which are
  1241.      * marked with X's in the figure below:
  1242.      *
  1243.      *                  * * *
  1244.      *                  *          *
  1245.      *               *      * *      *
  1246.      *             *    *         *    *
  1247.      *            X   *             *   X
  1248.      *               *               *
  1249.      *
  1250.      * The code below is tricky because it has to handle eccentricity
  1251.      * in the shape of the oval.  The key in the code below is to
  1252.      * realize that the slope of the line from arcPtr->center1 to corner1
  1253.      * is (boxWidth*sin1)/(boxHeight*cos1), and similarly for arcPtr->center2
  1254.      * and corner2.  These formulas can be computed from the formula for
  1255.      * the oval.
  1256.      */
  1257.  
  1258.     halfWidth = arcPtr->width/2.0;
  1259.     angle = atan2(boxWidth*sin1, boxHeight*cos1);
  1260.     corner1[0] = arcPtr->center1[0] + cos(angle)*halfWidth;
  1261.     corner1[1] = arcPtr->center1[1] + sin(angle)*halfWidth;
  1262.     angle = atan2(boxWidth*sin2, boxHeight*cos2);
  1263.     corner2[0] = arcPtr->center2[0] + cos(angle)*halfWidth;
  1264.     corner2[1] = arcPtr->center2[1] + sin(angle)*halfWidth;
  1265.  
  1266.     /*
  1267.      * For a chord outline, generate a six-sided polygon with three
  1268.      * points for each end of the chord.  The first and third points
  1269.      * for each end are butt points generated on either side of the
  1270.      * center point.  The second point is the corner point.
  1271.      */
  1272.  
  1273.     if (arcPtr->style == chordUid) {
  1274.     outlinePtr[0] = outlinePtr[12] = corner1[0];
  1275.     outlinePtr[1] = outlinePtr[13] = corner1[1];
  1276.     TkGetButtPoints(arcPtr->center2, arcPtr->center1,
  1277.         (double) arcPtr->width, 0, outlinePtr+10, outlinePtr+2);
  1278.     outlinePtr[4] = arcPtr->center2[0] + outlinePtr[2]
  1279.         - arcPtr->center1[0];
  1280.     outlinePtr[5] = arcPtr->center2[1] + outlinePtr[3]
  1281.         - arcPtr->center1[1];
  1282.     outlinePtr[6] = corner2[0];
  1283.     outlinePtr[7] = corner2[1];
  1284.     outlinePtr[8] = arcPtr->center2[0] + outlinePtr[10]
  1285.         - arcPtr->center1[0];
  1286.     outlinePtr[9] = arcPtr->center2[1] + outlinePtr[11]
  1287.         - arcPtr->center1[1];
  1288.     } else if (arcPtr->style == pieSliceUid) {
  1289.     /*
  1290.      * For pie slices, generate two polygons, one for each side
  1291.      * of the pie slice.  The first arm has a shape like this,
  1292.      * where the center of the oval is X, arcPtr->center1 is at Y, and
  1293.      * corner1 is at Z:
  1294.      *
  1295.      *     _____________________
  1296.      *    |              \
  1297.      *    |               \
  1298.      *    X             Y  Z
  1299.      *    |               /
  1300.      *    |_____________________/
  1301.      *
  1302.      */
  1303.  
  1304.     TkGetButtPoints(arcPtr->center1, vertex, (double) arcPtr->width, 0,
  1305.         outlinePtr, outlinePtr+2);
  1306.     outlinePtr[4] = arcPtr->center1[0] + outlinePtr[2] - vertex[0];
  1307.     outlinePtr[5] = arcPtr->center1[1] + outlinePtr[3] - vertex[1];
  1308.     outlinePtr[6] = corner1[0];
  1309.     outlinePtr[7] = corner1[1];
  1310.     outlinePtr[8] = arcPtr->center1[0] + outlinePtr[0] - vertex[0];
  1311.     outlinePtr[9] = arcPtr->center1[1] + outlinePtr[1] - vertex[1];
  1312.     outlinePtr[10] = outlinePtr[0];
  1313.     outlinePtr[11] = outlinePtr[1];
  1314.  
  1315.     /*
  1316.      * The second arm has a shape like this:
  1317.      *
  1318.      *
  1319.      *       ______________________
  1320.      *      /              \
  1321.      *     /               \
  1322.      *    Z  Y            X  /
  1323.      *     \              /
  1324.      *      \______________________/
  1325.      *
  1326.      * Similar to above X is the center of the oval/circle, Y is
  1327.      * arcPtr->center2, and Z is corner2.  The extra jog out to the left
  1328.      * of X is needed in or to produce a butted joint with the
  1329.      * first arm;  the corner to the right of X is one of the
  1330.      * first two points of the first arm, depending on extent.
  1331.      */
  1332.  
  1333.     TkGetButtPoints(arcPtr->center2, vertex, (double) arcPtr->width, 0,
  1334.         outlinePtr+12, outlinePtr+16);
  1335.     if ((arcPtr->extent > 180) ||
  1336.         ((arcPtr->extent < 0) && (arcPtr->extent > -180))) {
  1337.         outlinePtr[14] = outlinePtr[0];
  1338.         outlinePtr[15] = outlinePtr[1];
  1339.     } else {
  1340.         outlinePtr[14] = outlinePtr[2];
  1341.         outlinePtr[15] = outlinePtr[3];
  1342.     }
  1343.     outlinePtr[18] = arcPtr->center2[0] + outlinePtr[16] - vertex[0];
  1344.     outlinePtr[19] = arcPtr->center2[1] + outlinePtr[17] - vertex[1];
  1345.     outlinePtr[20] = corner2[0];
  1346.     outlinePtr[21] = corner2[1];
  1347.     outlinePtr[22] = arcPtr->center2[0] + outlinePtr[12] - vertex[0];
  1348.     outlinePtr[23] = arcPtr->center2[1] + outlinePtr[13] - vertex[1];
  1349.     outlinePtr[24] = outlinePtr[12];
  1350.     outlinePtr[25] = outlinePtr[13];
  1351.     }
  1352. }
  1353.  
  1354. /*
  1355.  *--------------------------------------------------------------
  1356.  *
  1357.  * HorizLineToArc --
  1358.  *
  1359.  *    Determines whether a horizontal line segment intersects
  1360.  *    a given arc.
  1361.  *
  1362.  * Results:
  1363.  *    The return value is 1 if the given line intersects the
  1364.  *    infinitely-thin arc section defined by rx, ry, start,
  1365.  *    and extent, and 0 otherwise.  Only the perimeter of the
  1366.  *    arc is checked: interior areas (e.g. pie-slice or chord)
  1367.  *    are not checked.
  1368.  *
  1369.  * Side effects:
  1370.  *    None.
  1371.  *
  1372.  *--------------------------------------------------------------
  1373.  */
  1374.  
  1375. static int
  1376. HorizLineToArc(x1, x2, y, rx, ry, start, extent)
  1377.     double x1, x2;        /* X-coords of endpoints of line segment. 
  1378.                  * X1 must be <= x2. */
  1379.     double y;            /* Y-coordinate of line segment. */
  1380.     double rx, ry;        /* These x- and y-radii define an oval
  1381.                  * centered at the origin. */
  1382.     double start, extent;    /* Angles that define extent of arc, in
  1383.                  * the standard fashion for this module. */
  1384. {
  1385.     double tmp;
  1386.     double tx, ty;        /* Coordinates of intersection point in
  1387.                  * transformed coordinate system. */
  1388.     double x;
  1389.  
  1390.     /*
  1391.      * Compute the x-coordinate of one possible intersection point
  1392.      * between the arc and the line.  Use a transformed coordinate
  1393.      * system where the oval is a unit circle centered at the origin.
  1394.      * Then scale back to get actual x-coordinate.
  1395.      */
  1396.  
  1397.     ty = y/ry;
  1398.     tmp = 1 - ty*ty;
  1399.     if (tmp < 0) {
  1400.     return 0;
  1401.     }
  1402.     tx = sqrt(tmp);
  1403.     x = tx*rx;
  1404.  
  1405.     /*
  1406.      * Test both intersection points.
  1407.      */
  1408.  
  1409.     if ((x >= x1) && (x <= x2) && AngleInRange(tx, ty, start, extent)) {
  1410.     return 1;
  1411.     }
  1412.     if ((-x >= x1) && (-x <= x2) && AngleInRange(-tx, ty, start, extent)) {
  1413.     return 1;
  1414.     }
  1415.     return 0;
  1416. }
  1417.  
  1418. /*
  1419.  *--------------------------------------------------------------
  1420.  *
  1421.  * VertLineToArc --
  1422.  *
  1423.  *    Determines whether a vertical line segment intersects
  1424.  *    a given arc.
  1425.  *
  1426.  * Results:
  1427.  *    The return value is 1 if the given line intersects the
  1428.  *    infinitely-thin arc section defined by rx, ry, start,
  1429.  *    and extent, and 0 otherwise.  Only the perimeter of the
  1430.  *    arc is checked: interior areas (e.g. pie-slice or chord)
  1431.  *    are not checked.
  1432.  *
  1433.  * Side effects:
  1434.  *    None.
  1435.  *
  1436.  *--------------------------------------------------------------
  1437.  */
  1438.  
  1439. static int
  1440. VertLineToArc(x, y1, y2, rx, ry, start, extent)
  1441.     double x;            /* X-coordinate of line segment. */
  1442.     double y1, y2;        /* Y-coords of endpoints of line segment. 
  1443.                  * Y1 must be <= y2. */
  1444.     double rx, ry;        /* These x- and y-radii define an oval
  1445.                  * centered at the origin. */
  1446.     double start, extent;    /* Angles that define extent of arc, in
  1447.                  * the standard fashion for this module. */
  1448. {
  1449.     double tmp;
  1450.     double tx, ty;        /* Coordinates of intersection point in
  1451.                  * transformed coordinate system. */
  1452.     double y;
  1453.  
  1454.     /*
  1455.      * Compute the y-coordinate of one possible intersection point
  1456.      * between the arc and the line.  Use a transformed coordinate
  1457.      * system where the oval is a unit circle centered at the origin.
  1458.      * Then scale back to get actual y-coordinate.
  1459.      */
  1460.  
  1461.     tx = x/rx;
  1462.     tmp = 1 - tx*tx;
  1463.     if (tmp < 0) {
  1464.     return 0;
  1465.     }
  1466.     ty = sqrt(tmp);
  1467.     y = ty*ry;
  1468.  
  1469.     /*
  1470.      * Test both intersection points.
  1471.      */
  1472.  
  1473.     if ((y > y1) && (y < y2) && AngleInRange(tx, ty, start, extent)) {
  1474.     return 1;
  1475.     }
  1476.     if ((-y > y1) && (-y < y2) && AngleInRange(tx, -ty, start, extent)) {
  1477.     return 1;
  1478.     }
  1479.     return 0;
  1480. }
  1481.  
  1482. /*
  1483.  *--------------------------------------------------------------
  1484.  *
  1485.  * AngleInRange --
  1486.  *
  1487.  *    Determine whether the angle from the origin to a given
  1488.  *    point is within a given range.
  1489.  *
  1490.  * Results:
  1491.  *    The return value is 1 if the angle from (0,0) to (x,y)
  1492.  *    is in the range given by start and extent, where angles
  1493.  *    are interpreted in the standard way for ovals (meaning
  1494.  *    backwards from normal interpretation).  Otherwise the
  1495.  *    return value is 0.
  1496.  *
  1497.  * Side effects:
  1498.  *    None.
  1499.  *
  1500.  *--------------------------------------------------------------
  1501.  */
  1502.  
  1503. static int
  1504. AngleInRange(x, y, start, extent)
  1505.     double x, y;        /* Coordinate of point;  angle measured
  1506.                  * from origin to here, relative to x-axis. */
  1507.     double start;        /* First angle, degrees, >=0, <=360. */
  1508.     double extent;        /* Size of arc in degrees >=-360, <=360. */
  1509. {
  1510.     double diff;
  1511.  
  1512.     diff = -atan2(y, x);
  1513.     diff = diff*(180.0/PI) - start;
  1514.     while (diff > 360.0) {
  1515.     diff -= 360.0;
  1516.     }
  1517.     while (diff < 0.0) {
  1518.     diff += 360.0;
  1519.     }
  1520.     if (extent >= 0) {
  1521.     return diff <= extent;
  1522.     }
  1523.     return (diff-360.0) >= extent;
  1524. }
  1525.